home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
commands
/
fsck.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
34KB
|
1,363 lines
/* fsck - file system checker Author: Robbert van Renesse */
/* Modified by Norbert Schlenker
* Removed vestiges of standalone/DOS versions:
* - various unused variables and buffers removed
* - now uses library functions rather than private internal routines
* - bytewise structure copies replaced by structure assignment
* - fixed one bug with 14 character file names
* - other small tweaks for speed
*
* Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
* Removed -m option, by which fsck could be told to make a file
* system on a 360K floppy. The code had limited utility, was buggy,
* and failed due to a bug in the ACK C compiler. Use mkfs instead!
*/
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
#include "../fs/const.h"
#include "../fs/type.h"
#undef printf /* defined as printk in "../fs/const.h" */
#include <stdio.h>
#if INTEL_32BITS
#define BITSHIFT 5 /* = log2(#bits(int)) */
#else
#define BITSHIFT 4 /* = log2(#bits(int)) */
#endif
#define BITMAPSHIFT 13 /* = log2(#bits(block)); 13 means 1K blocks */
#define MAXPRINT 8 /* max. number of error lines in chkmap */
#define MAXDIRSIZE 5000 /* max. size of a reasonable directory */
#define CINDIR 128 /* number of indirect zno's read at a time */
#define CDIRECT 16 /* number of dir entries read at a time */
#define BITMASK ((1 << BITSHIFT) - 1)
#define setbit(w, b) (w[(b) >> BITSHIFT] |= 1 << ((b) & BITMASK))
#define clrbit(w, b) (w[(b) >> BITSHIFT] &= ~(1 << ((b) & BITMASK)))
#define bitset(w, b) (w[(b) >> BITSHIFT] & (1 << ((b) & BITMASK)))
#define ZONE_CT 360 /* default zones (when making file system) */
#define INODE_CT 95 /* default inodes (when making file system) */
/* DEBUG FIXME. This and other things repeat stuff from fs, not necessarily
* identically. This is part of a structure in fs/super.h, and old versions
* had the wrong type for s_magic.
*/
struct dsb {
ino_t s_ninodes; /* # inodes on the minor device */
zone_nr s_nzones; /* total dev size, incl. bit maps etc */
unsigned short s_imap_blocks; /* # of blocks used by inode bit map */
unsigned short s_zmap_blocks; /* # of blocks used by zone bit map */
zone_nr s_firstdatazone; /* number of first data zone */
short s_log_zone_size; /* log2 of blocks/zone */
off_t s_maxsize; /* maximum file size on this device */
short s_magic; /* magic number for super blocks */
} sb;
#define STICKY_BIT 01000 /* not defined anywhere else */
/* Ztob gives the block address of a zone
* btoa gives the byte address of a block
*/
#define ztob(z) ((block_nr) (z) << sb.s_log_zone_size)
#define btoa(b) ((long) (b) * BLOCK_SIZE)
#define SCALE ((int) ztob(1)) /* # blocks in a zone */
#define FIRST sb.s_firstdatazone /* as the name says */
/* # blocks of each type */
#define N_SUPER 1
#define N_IMAP (sb.s_imap_blocks)
#define N_ZMAP (sb.s_zmap_blocks)
#define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
#define N_DATA (sb.s_nzones - FIRST)
/* Block address of each type */
#define BLK_SUPER (SUPER_BLOCK)
#define BLK_IMAP (BLK_SUPER + N_SUPER)
#define BLK_ZMAP (BLK_IMAP + N_IMAP)
#define BLK_ILIST (BLK_ZMAP + N_ZMAP)
#define BLK_FIRST ztob(FIRST)
#define ZONE_SIZE ((int) ztob(BLOCK_SIZE))
#define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
/* Byte address of a zone/of an inode */
#define zaddr(z) btoa(ztob(z))
#define inoaddr(i) ((long) (i - 1) * INODE_SIZE + btoa(BLK_ILIST))
#define INDCHUNK (CINDIR * ZONE_NUM_SIZE)
#define DIRCHUNK (CDIRECT * DIR_ENTRY_SIZE)
char *prog, *device; /* program name (fsck), device name */
int firstcnterr; /* is this the first inode ref cnt error? */
unsigned *imap, *spec_imap; /* inode bit maps */
unsigned *zmap, *spec_zmap; /* zone bit maps */
unsigned *dirmap; /* directory (inode) bit map */
char rwbuf[BLOCK_SIZE]; /* one block buffer cache */
block_nr thisblk; /* block in buffer cache */
char nullbuf[BLOCK_SIZE]; /* null buffer */
nlink_t *count; /* inode count */
int changed; /* has the diskette been written to? */
struct stack {
dir_struct *st_dir;
struct stack *st_next;
char st_presence;
} *ftop;
int dev; /* file descriptor of the device */
#define DOT 1
#define DOTDOT 2
/* Counters for each type of inode/zone. */
int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
int npipe, nfreezone, ztype[NLEVEL];
int repair, automatic, listing, listsuper; /* flags */
int firstlist; /* has the listing header been printed? */
unsigned part_offset; /* sector offset for this partition */
char answer[] = {"Answer questions with y or n. Then hit RETURN"};
/* Initialize the variables used by this program. */
initvars()
{
register level;
nregular = ndirectory = nblkspec = ncharspec = nbadinode = npipe = 0;
for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
changed = 0;
thisblk = NO_BLOCK;
firstlist = 1;
firstcnterr = 1;
}
/* Print the string `s' and exit. */
void fatal(s)
char *s;
{
printf("%s\nfatal\n", s);
exit(-1);
}
/* Test for end of line. */
eoln(c)
{
return(c == EOF || c == '\n' || c == '\r');
}
/* Ask a question and get the answer unless automatic is set. */
int yes(question)
char *question;
{
register c, answer;
if (!repair) {
printf("\n");
return(0);
}
printf("%s? ", question);
if (automatic) {
printf("yes\n");
return(1);
}
fflush(stdout);
if ((c = answer = getchar()) == 'q' || c == 'Q') exit(1);
while (!eoln(c)) c = getchar();
return !(answer == 'n' || answer == 'N');
}
/* Convert string to integer. Representation is octal. */
int atoo(s)
register char *s;
{
register int n = 0;
while ('0' <= *s && *s < '8') {
n <<= 3;
n += *s++ - '0';
}
return n;
}
/* If repairing the file system, print a prompt and get a string from user. */
input(buf, size)
char *buf;
{
register char *p = buf;
printf("\n");
if (repair) {
printf("--> ");
fflush(stdout);
while (--size) {
*p = getchar();
if (eoln(*p)) {
*p = 0;
return(p > buf);
}
p++;
}
*p = 0;
while (!eoln(getchar()));
return(1);
}
return(0);
}
/* Allocate some memory and zero it. */
char *alloc(nelem, elsize)
unsigned nelem, elsize;
{
char *p;
if ((p = (char *) malloc(nelem * elsize)) == 0) fatal("out of memory");
memset(p, 0, nelem * elsize);
return(p);
}
/* Print the name in a directory entry. */
void printname(s)
char *s;
{
register n = NAME_MAX;
int c;
do {
if ((c = *s) == 0) break;
if (!isprint(c)) c = '?';
putchar(c);
s++;
} while (--n);
}
/* Print the pathname given by a linked list pointed to by `sp'. The
* names are in reverse order.
*/
printrec(sp)
struct stack *sp;
{
if (sp->st_next != 0) {
printrec(sp->st_next);
putchar('/');
printname(sp->st_dir->d_name);
}
}
/* Print the current pathname. */
printpath(mode, nlcr)
{
if (ftop->st_next == 0)
putchar('/');
else
printrec(ftop);
switch (mode) {
case 1:
printf(" (ino = %u, ", ftop->st_dir->d_inum);
break;
case 2:
printf(" (ino = %u)", ftop->st_dir->d_inum);
break;
}
if (nlcr) printf("\n");
}
/* Open the device. */
devopen()
{
if ((dev = open(device, repair ? O_RDWR : O_RDONLY)) < 0) {
perror(device);
fatal("");
}
}
/* Close the device. */
devclose()
{
if (close(dev) != 0) {
perror("close");
fatal("");
}
}
/* Read or write a block. */
devio(bno, dir)
block_nr bno;
{
if (dir == READING && bno == thisblk) return;
thisblk = bno;
lseek(dev, btoa(bno), SEEK_SET);
if (dir == READING) {
if (read(dev, rwbuf, BLOCK_SIZE) == BLOCK_SIZE)
return;
} else {
if (write(dev, rwbuf, BLOCK_SIZE) == BLOCK_SIZE)
return;
}
printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
dir == READING ? "read" : "write", (long) bno, errno);
fatal("");
}
/* Read `size' bytes from the disk starting at byte `offset'. */
devread(offset, buf, size)
long offset;
char *buf;
{
devio((block_nr) (offset / BLOCK_SIZE), READING);
memmove(buf, &rwbuf[(int) (offset % BLOCK_SIZE)], size);
}
/* Write `size' bytes to the di